package study.eggs.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

public final class MethodUtils {

    private MethodUtils() {
    }

    /**
     * 获取对象所有 Method
     *
     * @param obj -对象
     * @return Method[]
     */
    public static Method[] getAllMethod(Object obj) {
        if (Objects.isNull(obj)) {
            return null;
        }
        Method[] methods = obj.getClass().getDeclaredMethods();
        return methods;
    }

    /**
     * 获取对象指定 Method
     *
     * @param obj            -对象
     * @param name           -方法名
     * @param parameterTypes -参数类型
     * @return Method
     */
    public static Method getMethod(Object obj, String name,
                                   Class<?>... parameterTypes) {
        if (Objects.isNull(obj)) {
            return null;
        }
        Method method;
        try {
            method = obj.getClass().getDeclaredMethod(name, parameterTypes);
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException("get method error!", ex);
        }
        return method;
    }

    /**
     * 获取对象指定Method
     *
     * @param obj  -对象
     * @param name -方法名
     * @return Method
     */
    public static Method getMethod(Object obj, String name) {
        if (Objects.isNull(obj)) {
            return null;
        }
        Method method = Arrays.stream(getAllMethod(obj))
                .filter(m -> Objects.equals(name, m.getName()))
                .findFirst()
                .get();
        return method;
    }

    /**
     * 调用方法
     *
     * @param obj    -对象
     * @param method -方法
     * @param params -参数
     * @return Object
     */
    public Object invoke(Object obj, Method method, Object... params) {
        Object result;
        try {
            result = method.invoke(obj, params);
        } catch (InvocationTargetException | IllegalAccessException ex) {
            throw new RuntimeException("invoke method error!", ex);
        }
        return result;
    }
}
